Layout Exercises
Toggle, Revisited
Earlier, we saw how to build a <Toggle /> component using Framer Motion:
We solved it in that example using the animate property, but now that we know about layout animations, there might be a better way!
Your mission is to update the code below so that it uses layout animations.
Acceptance Criteria:
- The
Togglecomponent should not use theanimateproperty. Instead, the ball's position should be controlled with CSS, and it should be animated using a layout animation.
Code Playground
import React from 'react';
import { motion } from 'framer-motion';
import styles from './Toggle.module.css';
function Toggle({ value, onChange, ...delegated }) {
return (
<button
type="button"
role="switch"
aria-checked={value}
className={styles.wrapper}
onClick={() => onChange(!value)}
{...delegated}
>
<motion.span
className={styles.ball}
initial={false}
transition={{
type: 'spring',
stiffness: 500,
damping: 40,
}}
animate={{
x: value ? '100%' : '0%',
}}
/>
</button>
);
}
export default Toggle;
Solution:
Flex Demo
Let's recreate the “FlexDemo” component from my blog post, An Interactive Guide to Flexbox!
Most of the code has already been provided. Your mission is to apply the Flexbox settings according to the state variables, and to animate it using Framer Motion.
Acceptance Criteria:
- The
flexDirection,justifyContent, andalignItemsstate variables should be applied as an inline style to thedemoAreaelement. - Framer Motion layout animations should be used to animate changing the various parameters.
- The text should not be distorted when switching between parameters (for example,
alignItemsshould be able to switch betweenstretchandcenterwithout any text warping).
Code Playground
import React from 'react';
import { motion } from 'framer-motion';
import styles from './FlexDemo.module.css';
function FlexDemo() {
const [flexDirection, setFlexDirection] = React.useState('row');
const [justifyContent, setJustifyContent] =
React.useState('flex-start');
const [alignItems, setAlignItems] = React.useState('stretch');
return (
<section className={styles.wrapper}>
<div className={styles.demoArea}>
{ITEMS.map((item) => (
<div key={item.id} className={styles.flexItem}>
{item.label}
</div>
))}
</div>
<div className={styles.controls}>
<SelectControl
label="flex-direction"
value={flexDirection}
onChange={(event) => setFlexDirection(event.target.value)}
>
<option value="row">row</option>
<option value="column">column</option>
</SelectControl>
<SelectControl
label="justify-content"
value={justifyContent}
onChange={(event) =>
setJustifyContent(event.target.value)
}
>
<option value="flex-start">flex-start</option>
<option value="flex-end">flex-end</option>
<option value="center">center</option>
<option value="space-between">space-between</option>
<option value="space-around">space-around</option>
<option value="space-evenly">space-evenly</option>
</SelectControl>
<SelectControl
label="align-items"
value={alignItems}
onChange={(event) => setAlignItems(event.target.value)}
>
<option value="stretch">stretch</option>
<option value="flex-start">flex-start</option>
Solution: